package com.ibm.ibank.dubbo.gateway.server;

import com.alibaba.fastjson.JSON;
import com.ibm.ibank.dubbo.gateway.dto.ServiceCallData;
import com.ibm.ibank.dubbo.gateway.dto.ServiceDef;
import com.ibm.ibank.dubbo.gateway.metadata.MetadataCollector;
import com.ibm.ibank.dubbo.gateway.utils.NamingThreadFactory;
import com.ibm.ibank.dubbo.gateway.worker.RequestWorker;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.QueryStringDecoder;
import io.netty.util.CharsetUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;


@ChannelHandler.Sharable
public class HttpProcessHandler extends SimpleChannelInboundHandler<FullHttpRequest> {

    private ExecutorService businessThreadPool;
    private MetadataCollector metadataCollector;
    private Map<String, String> appPackageMap;
    private Logger logger = LoggerFactory.getLogger(HttpProcessHandler.class);


    public HttpProcessHandler(int businessThreadCount, MetadataCollector metadataCollector, Map<String, String> appPackageMap) {
        super();
        this.businessThreadPool = Executors.newFixedThreadPool(businessThreadCount, new NamingThreadFactory("Dubbo-proxy-request-worker"));
        this.metadataCollector = metadataCollector;
        this.appPackageMap = appPackageMap;
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) {
        ctx.flush();
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest msg) {

        QueryStringDecoder queryStringDecoder = new QueryStringDecoder(msg.uri());
        String path = queryStringDecoder.rawPath();
        if (path.endsWith("/")) {
            path = path.substring(0, path.length() - 1);
        }
        if (path.startsWith("/")) {
            path = path.substring(1);
        }
        if (path.contains("/")) {
            ServiceDef serviceDef = new ServiceDef();
            String[] paths = path.split("/");

            serviceDef.setServiceID(paths[1]);
            serviceDef.setApplication(paths[0]);
            serviceDef.setMethodName(paths[2]);
            serviceDef.setInterfaze(appPackageMap.get(serviceDef.getApplication()) + "." + serviceDef.getServiceID());

            Map<String, List<String>> params = queryStringDecoder.parameters();
            if (params.containsKey("group")) {
                //service = params.get("group").get(0) + "/" + service;
                serviceDef.setGroup(params.get("group").get(0));
            }
            if (params.containsKey("version")) {
                //service = service + ":" + params.get("version").get(0);
                serviceDef.setVersion(params.get("version").get(0));
            }

            ByteBuf raw = msg.content();
            String info = raw.toString(CharsetUtil.UTF_8);
            Object paramValue = JSON.parse(info);

            ServiceCallData serviceCallData = new ServiceCallData(serviceDef, new Object[]{paramValue});
            doRequest(ctx, serviceCallData, msg);
        }  else {
            //TODO error handle
        }
    }

    private void doRequest(ChannelHandlerContext ctx, ServiceCallData serviceCallData, HttpRequest msg) {
        businessThreadPool.execute(new RequestWorker(serviceCallData, ctx, msg, metadataCollector));
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        cause.printStackTrace();
        ctx.close();
    }
}
